﻿using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;

namespace Yoozoo.Managers.ResourceManagement
{
    public class BuildPlayer
    {
        public static string[] GetBuildScenes()
        {
            List<string> names = new List<string>();

            foreach (EditorBuildSettingsScene e in EditorBuildSettings.scenes)
            {
                if (e == null)
                {
                    continue;
                }

                if (e.enabled)
                {
                    names.Add(e.path);
                }
            }

            return names.ToArray();
        }

        public static void Build(
            string path, 
            string channel, 
            string bundleVersion, 
            string bundleVersionCode, 
            bool development, 
            bool isUpdateResource, 
            bool isLog = true, 
            PackageResourceType packageResourceType = PackageResourceType.Full, 
            string appConfigPath = null, 
            string subPackage = "full", 
            bool fastMode = false,
            bool autoDebug = false,
            bool isExportProject = false,
            int architecture = -1,
            bool buildApkPerCpuArchitecture = false,
            bool isFirstPackage = false,
            bool isDeepMode = false,
            bool isAutoProfiler = false)
        {
            string[] scenes = GetBuildScenes();
            if (!CheckSceneAndPath(scenes, path))
            {
                UnityEngine.Debug.LogError("you must Add one Scene to BuildSettings");
                return;
            }
            
            PlayerSettings.bundleVersion = bundleVersion;
            BuildAppConfigUnit appConfigUnit = BuildConfigManager.SetPlayerSettings(channel);
            AppConfig.SetAppConfig(bundleVersion, int.Parse(bundleVersionCode), 
                appConfigUnit.channelName, appConfigUnit.isSDK, isUpdateResource, isLog, isLog, 
                (int)packageResourceType, subPackage, appConfigUnit.serverVersionPath, 
                appConfigUnit.serverListPath, appConfigUnit.maintenanceUrl, isFirstPackage, appConfigUnit.serverApiPath, 
                appConfigUnit.secondaryServerVersionPath1, appConfigUnit.secondaryServerVersionPath2,
                appConfigUnit.serverPath,appConfigUnit.showDebugBtn);
            SetGraphicsAPIs();
            
#if UNITY_IOS
            if (Directory.Exists(path))
            {
                Directory.Delete(path,true);
            }

            Directory.CreateDirectory(path);
            SetBuildPlatformTool.SetGTCompatibleWithPlatform(Application.dataPath + "/Plugins/GTTest/iOS/","GT",BuildTarget.iOS);
            BuildIos(bundleVersionCode, development);
            Build(scenes, path, BuildTarget.iOS, development,autoDebug,isDeepMode,isAutoProfiler);
            
#elif UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX
            string directoryName = Path.GetDirectoryName(path);
            if (Directory.Exists(directoryName))
            {
                Directory.Delete(directoryName,true);
            }
            PlayerSettings.SetScriptingBackend(BuildTargetGroup.Standalone, ScriptingImplementation.IL2CPP);
            UnityEditor.WindowsStandalone.UserBuildSettings.createSolution = false;
            Build(scenes, path, BuildTarget.StandaloneWindows64, development,autoDebug,isDeepMode,isAutoProfiler);
#else
            string directoryName = Path.GetDirectoryName(path);
            if (!Directory.Exists(directoryName))
            {
                Directory.CreateDirectory(directoryName);
            }

            // 非SDK情况，不从SuperSdkApplication启动，直接从UnityPlayer启动
            if (!appConfigUnit.isSDK)
            {
                string androidManifest = Path.Combine(Application.dataPath, "Plugins/Android/AndroidManifest.xml");
                string androidManifestNoSdk = Path.Combine(Application.dataPath, "Plugins/Android/AndroidManifest-NoSdk.xml");
                if (File.Exists(androidManifest) && File.Exists(androidManifestNoSdk))
                {
                    File.Delete(androidManifest);
                    File.Copy(androidManifestNoSdk, androidManifest);
                }
            }
            
            BuildAndroid(bundleVersionCode, fastMode, isExportProject, architecture, buildApkPerCpuArchitecture);
            Build(scenes, path, BuildTarget.Android, development,autoDebug,isDeepMode,isAutoProfiler);
#endif
        }

        public static void SetGraphicsAPIs()
        {
#if UNITY_IOS
             PlayerSettings.SetGraphicsAPIs(BuildTarget.iOS,new GraphicsDeviceType[]
            {
                GraphicsDeviceType.Metal
            });
#elif UNITY_ANDROID
            PlayerSettings.SetGraphicsAPIs(BuildTarget.Android,new GraphicsDeviceType[]
            {
                GraphicsDeviceType.OpenGLES3
            });
#elif UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX
            PlayerSettings.SetGraphicsAPIs(BuildTarget.StandaloneWindows64, new GraphicsDeviceType[]
            {
                GraphicsDeviceType.Direct3D11
            });
#endif
        }

        public static bool ContainsDefineSymbol(string symbols)
        {
            BuildTargetGroup targetGroup = BuildTargetGroup.Android;
#if UNITY_IOS
            targetGroup = BuildTargetGroup.iOS;
#elif UNITY_STANDALONE_WIN || UNITY_STANDALONE_OSX
            targetGroup = BuildTargetGroup.Standalone;
#endif
            string ori = PlayerSettings.GetScriptingDefineSymbolsForGroup(targetGroup);
            List<string> defineSymbols = new List<string>(ori.Split(';'));
            bool isSymbols = defineSymbols.Contains(symbols);

            return defineSymbols.Contains(symbols);
        }

        public static void BuildAndroid(string bundleVersionCode, bool fastMode, bool isExportProject = false, 
            int architecture = -1, bool buildApkPerCpuArchitecture = false)
        {
            PlayerSettings.Android.bundleVersionCode = int.Parse(bundleVersionCode);
            // EditorUserBuildSettings.androidDebugMinification = AndroidMinification.None;
            // EditorUserBuildSettings.androidReleaseMinification = AndroidMinification.None;
            EditorUserBuildSettings.androidBuildSystem = AndroidBuildSystem.Gradle;
            EditorUserBuildSettings.exportAsGoogleAndroidProject = isExportProject;
            EditorUserBuildSettings.androidCreateSymbols = isExportProject ? AndroidCreateSymbols.Debugging : AndroidCreateSymbols.Disabled;

            var scriptingImplementation = ScriptingImplementation.IL2CPP;
            if (fastMode)
                scriptingImplementation = ScriptingImplementation.Mono2x;
            PlayerSettings.SetScriptingBackend(BuildTargetGroup.Android, scriptingImplementation);

            Debug.Log($"BuildPlayer.BuildAndroid: architecture = {(AndroidArchitecture)architecture}, buildApkPerCpuArchitecture = {buildApkPerCpuArchitecture}");
            if (Application.isBatchMode)
            {
                if (architecture > 0)
                {
                    PlayerSettings.Android.targetArchitectures = (AndroidArchitecture) architecture;
                }
                else
                {
                    PlayerSettings.Android.targetArchitectures = AndroidArchitecture.All;
                }
            }

            // Split APKs by target architecture(Experiment)
            PlayerSettings.Android.buildApkPerCpuArchitecture = buildApkPerCpuArchitecture;
        }

        static void BuildIos(string bundleVersionCode, bool isDevelopment)
        {
            PlayerSettings.iOS.buildNumber = bundleVersionCode;
            PlayerSettings.iOS.appleEnableAutomaticSigning = true;
            PlayerSettings.iOS.hideHomeButton = true;
            PlayerSettings.iOS.deferSystemGesturesMode = UnityEngine.iOS.SystemGestureDeferMode.All;
            if (!isDevelopment)
            {
                // for CrashSight <https://crashsight.qq.com/>
                PlayerSettings.iOS.scriptCallOptimization = ScriptCallOptimizationLevel.SlowAndSafe;
            }
            EditorUserBuildSettings.symlinkSources = false;
        }

        /// <summary>
        /// 检查场景和打包路径
        /// 如果场景或路径为空返回false
        /// </summary>
        /// <param name="scenes">打包的场景</param>
        /// <param name="path">打包路径</param>
        private static bool CheckSceneAndPath(string[] scenes, string path)
        {
            if (scenes == null || scenes.Length == 0 || path == null)
            {
                return false;
            }
            return true;
        }

        private static void Build(string[] scenes, string path, BuildTarget target, bool isDevelopment,bool autoDebug,bool isDeepMode = false,bool isAutoProfiler = false)
        {
            BuildOptions options = BuildOptions.None;
            if (isDevelopment) options = options | BuildOptions.Development;
            if(autoDebug) options = options | BuildOptions.AllowDebugging;
            if (isDeepMode) options = options | BuildOptions.EnableDeepProfilingSupport;
            if(isAutoProfiler) options = options | BuildOptions.ConnectWithProfiler;
            BuildPipeline.BuildPlayer(scenes, path, target, options);
        }
    }
}
